package core.hmxchen.log.handler;

import core.hmxchen.log.entity.MethodInfo;
import core.hmxchen.log.enums.Level;
import org.slf4j.Logger;

import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @program: log-print
 * @description: 日志处理类
 * @author: hmxchen
 * @create: 2021-09-03 14:05
 **/
public class LogHandler {
    public static final String TIME_KEY = "【TIME】:";

    /***
     * @创建人: hmxchen
     * @创建时间: 2021/9/3 14:05
     * @描述: 判断是否开启了日志打印
     * @参数0: log
     * @返回: boolean
     */
    public static boolean isEnable(Logger log) {
        return log.isDebugEnabled() ||
                log.isInfoEnabled() ||
                log.isWarnEnabled() ||
                log.isErrorEnabled() ||
                log.isTraceEnabled();
    }

    /**
     * 是否参数过滤
     *
     * @param filterParamNames 过滤参数名称列表
     * @param paramName        带过滤参数名称
     * @return 返回布尔值，过滤true，否则false
     */
    public static boolean isParamFilter(String[] filterParamNames, String paramName) {
        for (String name : filterParamNames) {
            if (name.equals(paramName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取日志信息字符串
     *
     * @param busName          业务名
     * @param methodInfo       方法信息
     * @param params           参数值
     * @param filterParamNames 过滤参数列表
     * @return 返回日志信息字符串
     */
    public static String getBeforeInfo(
            String busName,
            MethodInfo methodInfo,
            Object[] params,
            String[] filterParamNames
    ) {
        return createInfoBuilder(busName, methodInfo)
                .append("【传入参数】：【").append(
                        getParamMap(
                                methodInfo.getParamNames(),
                                params,
                                filterParamNames
                        )
                ).append("】\n").toString();
    }

    /**
     * 获取日志信息字符串
     *
     * @param busName    业务名
     * @param methodInfo 方法信息
     * @param result     返回结果
     * @return 返回日志信息字符串
     */
    public static String getAfterInfo(String busName, MethodInfo methodInfo, Object result) {
        return createInfoBuilder(busName, methodInfo)
                .append("【返回结果】：【").append(parseParam(result)).append("】\n").toString();
    }

    /**
     * 获取日志信息字符串
     *
     * @param busName          业务名
     * @param methodInfo       方法信息
     * @param params           参数值
     * @param filterParamNames 过滤参数列表
     * @param result           返回结果
     * @return 返回日志信息字符串
     */
    public static String getAroundInfo(
            String busName,
            MethodInfo methodInfo,
            Object[] params,
            String[] filterParamNames,
            Object result,
            Throwable e
    ) {
        String TIME = "";
        if (result != null) {
            int index = result.toString().indexOf(TIME_KEY);
            TIME = result.toString().substring(index + TIME_KEY.length());
            result = result.toString().substring(0, index);
        }
        return createInfoBuilder(busName, methodInfo)
                .append("【传入参数】：【").append(
                        getParamMap(
                                methodInfo.getParamNames(),
                                params,
                                filterParamNames
                        )
                ).append("】\n").append("【返回结果】：【")
                .append(e != null ? "执行异常(" + e.getLocalizedMessage() + ")" : parseParam(result)
                ).append("】\n")
                .append("【执行耗时】：").append(TIME + "ms\n")
                .toString();
    }

    /**
     * 获取日志信息字符串
     *
     * @param busName    业务名
     * @param methodInfo 方法信息
     * @return 返回日志信息字符串
     */
    public static String getThrowingInfo(String busName, MethodInfo methodInfo, Throwable e) {
        return createInfoBuilder(busName, methodInfo).append("【异常信息】:").append(e.getLocalizedMessage()).toString();
    }


    /**
     * 创建日志信息builder
     *
     * @param busName    业务名
     * @param methodInfo 方法信息
     * @return 返回日志信息builder
     */
    public static StringBuilder createInfoBuilder(String busName, MethodInfo methodInfo) {
        StringBuilder builder = new StringBuilder();
        builder.append("\n【调用时间】：【").append(new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(new Date())).append("】\n");
        builder.append("【调用方法】：【");
        if (methodInfo.isNative()) {
            builder.append(methodInfo.getClassAllName()).append('.').append(methodInfo.getMethodName());
        } else {
            builder.append(createMethodStack(methodInfo));
        }
        return builder.append("】\n")
                .append("【业务名称】：【").append(busName).append("】\n");
    }

    /**
     * 获取参数字典
     *
     * @param paramNames       参数名称列表
     * @param paramValues      参数值数组
     * @param filterParamNames 过滤参数列表
     * @return 返回参数字典
     */
    public static Map<String, Object> getParamMap(List<String> paramNames, Object[] paramValues, String[] filterParamNames) {
        int count = paramNames.size();
        Map<String, Object> paramMap = new LinkedHashMap<>(count);
        if (count > 0) {
            if (filterParamNames != null && filterParamNames.length > 0) {
                for (int i = 0; i < count; i++) {
                    if (!isParamFilter(filterParamNames, paramNames.get(i))) {
                        paramMap.put(paramNames.get(i), parseParam(paramValues[i]));
                    }
                }
            } else {
                for (int i = 0; i < count; i++) {
                    paramMap.put(paramNames.get(i), parseParam(paramValues[i]));
                }
            }
        }
        return paramMap;
    }

    /**
     * 获取参数字典
     *
     * @param paramNames  参数名称列表
     * @param paramValues 参数值数组
     * @return 返回参数字典
     */
    public static Map<String, Object> getParamMap(List<String> paramNames, Object[] paramValues) {
        return getParamMap(paramNames, paramValues, null);
    }

    /**
     * 解析参数
     *
     * @param param 参数
     * @return 返回参数字符串
     */
    public static String parseParam(Object param) {
        if (param == null) {
            return null;
        }
        Class<?> paramClass = param.getClass();
        if (Map.class.isAssignableFrom(paramClass)) {
            return parseMap(param);
        }
        if (Iterable.class.isAssignableFrom(paramClass)) {
            return parseIterable(param);
        }
        return paramClass.isArray() ? parseArray(param) : param.toString();
    }

    /**
     * 解析字典
     *
     * @param param 参数值
     * @return 返回参数字典字符串
     */
    @SuppressWarnings("unchecked")
    public static String parseMap(Object param) {
        Map paramMap = (Map) param;
        Iterator<Map.Entry> iterator = paramMap.entrySet().iterator();
        if (!iterator.hasNext()) {
            return "{}";
        }
        StringBuilder builder = new StringBuilder();
        builder.append('{');
        Map.Entry entry;
        while (true) {
            entry = iterator.next();
            builder.append(entry.getKey()).append('=').append(parseParam(entry.getValue()));
            if (iterator.hasNext()) {
                builder.append(',').append(' ');
            } else {
                return builder.append('}').toString();
            }
        }
    }

    /**
     * 解析集合
     *
     * @param param 参数值
     * @return 返回参数列表字符串
     */
    public static String parseIterable(Object param) {
        Iterator iterator = ((Iterable) param).iterator();
        if (!iterator.hasNext()) {
            return "[]";
        }
        StringBuilder builder = new StringBuilder();
        builder.append('[');
        while (true) {
            builder.append(parseParam(iterator.next()));
            if (iterator.hasNext()) {
                builder.append(',').append(' ');
            } else {
                return builder.append(']').toString();
            }
        }
    }

    /**
     * 解析数组
     *
     * @param param 参数值
     * @return 返回参数列表字符串
     */
    public static String parseArray(Object param) {
        int length = Array.getLength(param);
        if (length == 0) {
            return "[]";
        }
        StringBuilder builder = new StringBuilder();
        builder.append('[');
        for (int i = 0; i < length; i++) {
            builder.append(parseParam(Array.get(param, i)));
            if (i + 1 < length) {
                builder.append(',').append(' ');
            }
        }
        return builder.append(']').toString();
    }

    /**
     * 创建方法栈
     *
     * @param methodInfo 方法信息
     * @return 返回栈信息
     */
    public static StackTraceElement createMethodStack(MethodInfo methodInfo) {
        return new StackTraceElement(
                methodInfo.getClassAllName(),
                methodInfo.getMethodName(),
                methodInfo.getClassSimpleName() + ".java",
                methodInfo.getLineNumber()
        );
    }

    /**
     * 打印信息
     *
     * @param log   日志对象
     * @param level 日志级别
     * @param msg   输出信息
     */
    public static void print(Logger log, Level level, String msg) {
        switch (level) {
            case DEBUG:
                log.debug(msg);
                break;
            case INFO:
                log.info(msg);
                break;
            case WARN:
                log.warn(msg);
                break;
            case ERROR:
                log.error(msg);
                break;
            default:
        }
    }
}
